package com.jml.security.config;

import com.jml.security.mobile.filter.SmsCodeAuthenticationSecurityConfig;
import com.jml.security.properties.SecurityProperties;
import com.jml.security.validate.ValidateCodeSecurityConfig;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
import org.springframework.security.web.session.InvalidSessionStrategy;
import org.springframework.security.web.session.SessionInformationExpiredStrategy;
import org.springframework.social.security.SpringSocialConfigurer;


@Configuration
public class BrowserSecurityConfig extends AbstractChannelSecurityConfig {

	@Autowired
	private SecurityProperties securityProperties;

	@Autowired
	private SmsCodeAuthenticationSecurityConfig smsCodeAuthenticationSecurityConfig;

	@Autowired
	private ValidateCodeSecurityConfig validateCodeSecurityConfig;

	@Autowired
	private DataSource dataSource;

	@Autowired
	private UserDetailsService userDetailsService;

	/*@Autowired
	private SpringSocialConfigurer jmlSocialSecurityConfig;
*/

	@Autowired
	private SessionInformationExpiredStrategy SessionInformationExpiredStrategy;

	@Autowired
	private InvalidSessionStrategy InvalidSessionStrategy;

	@Autowired
	private LogoutSuccessHandler logoutSuccessHandler;

	@Bean
	public PasswordEncoder passwordEncoder(){
		//BCryptPasswordEncoder可以换成自定义的加密类，但是需要继承PasswordEncoder，
		//在登录模块中用的加密其实就是这里的加密
		return new BCryptPasswordEncoder();
	}

	@Bean
	public PersistentTokenRepository persistentTokenRepository(){
		JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl();
		tokenRepository.setDataSource(dataSource);
		//启动创建表
		//tokenRepository.setCreateTableOnStartup(true);
		return tokenRepository;
	}

	@Override
	protected void configure(HttpSecurity http) throws Exception {


		applyPasswordAuthenticationConfig(http);
		http
				.apply(validateCodeSecurityConfig).and()
				.apply(smsCodeAuthenticationSecurityConfig).and()
				//.apply(jmlSocialSecurityConfig).and()
				.rememberMe()
					.tokenRepository(persistentTokenRepository())
					.tokenValiditySeconds(securityProperties.getBrowser().getRememberMeSeconds())
					.userDetailsService(userDetailsService)
					.and()
				.sessionManagement()
					//session失效访问的地址
					.invalidSessionStrategy(InvalidSessionStrategy)
					//最大登录数是1
					.maximumSessions(securityProperties.getBrowser().getSession().getMaximumSessions())
					//session的数量达到最大数量的时候阻止登录行为
					.maxSessionsPreventsLogin(securityProperties.getBrowser().getSession().isMaxSessionsPreventsLogin())
					//当session的数量超过登录数量的时候，让前面的session登录执行的操作
					.expiredSessionStrategy(SessionInformationExpiredStrategy)
					.and()
					.and()
				.logout()
					//设置退出的url
					.logoutUrl("/signOut")
					//退出成功的url:logoutSuccessUrl和logoutSuccessHandler是互斥的，如果有handle则url就失效了。
					.logoutSuccessHandler(logoutSuccessHandler)
					//退出成功的url
					//.logoutSuccessUrl("jml-logout.html")
					//退出时候删除cookie，参数是指定需要删除cookie的名字
					.deleteCookies("JSESSIONID")
					.and()
				//表示这个后面的请求都是需要授权的配置
				.authorizeRequests()
					//当访问这个"/jml-signIn.html" url的时候不需要认证，这是登录页面
					//.antMatchers("/jml-signIn.html").permitAll()
					.antMatchers("/authentication/require",
							"/jml-signIn",
							"/code/*",
							"/session/invalid",
							"/signOut",
							securityProperties.getBrowser().getLoginPage()).permitAll()
					.anyRequest().authenticated().and()
					//跨站请求伪造
				.csrf()
					.disable();
	}
}
